#include <stdio.h>

#include <archive.h>
#include <getopt.h>

void print_help(char * name)
{
printf("\
Usage: %s [options] FILE...\n"
,basename(name)
);
printf("\
Archi is a simple application that allows you to compress and decompress \n\
file(s) or/and number of directories using the modified Deflate's algorithm. \
\n\
Contact: pawel.lebioda89@gmail.com \n\
Website: http://code.google.com/p/archi-ve/ \n\
License: GNU GPL v2.0 (http://www.gnu.org/licenses/gpl-2.0.html) \n\
\n");
printf("Allowed options:\n");
printf("\
-h, --help                   give this help list\
\n");
printf("\
-q, --quiet                  will not display information on current operations\
\n");
printf("\
-x, --extract                extract file(s) from archive\
\n");
printf("\
-c, --create                 create archive from specified file or dir\
\n");
printf("\
-o, --out-file [FILE]        output file name or output direcory name\n\
                             if -x option all extracted files and directories\n\
                             will be placed in specified direcotry\n\
                             if -c option it is the name of archive, \n\
			     if not specified default output file name is input file's \n\
			     name extended by '.archi' (for -c option)\
\n");
printf("\
-w, --window-size [uint16]   window size - parameter of LZ77 algorithm\n\
                             This parameter affects the rate and extent of compression\n\
                             [Default: %d] \
\n",ARCHI_WINDOW_SIZE);
printf("\
-b, --buffer-size [uint16]   buffer size - parameter of LZ77 algorithm\n\
                             This parameter affects the rate and extent of compression\n\
                             [Default: %d]\
\n",ARCHI_BUFFER_SIZE);
printf("\
-r, --reset                  reset Huffman trees and LZ77's window and buffer\n\
                             This parameter may affects the rate and extent of compression\
\n");
printf("\nExamples:\n");    
printf("\
archi -c mydocs/                            # Create mydocs.archi archive from mydocs directory\
\n");
printf("\
archi -qc -o archive.foo file1.txt mydocs/  # Create archive.foo archive from file.txt and \n\
                                            # mydocs directory in quiet mode\
\n");
printf("\
archi -c -w 1024 -b 64 file.txt             # Create file.txt.archi archive from file.txt\n\
                                            # with window length 1024 and buffer length 64\
\n");
printf("\
archi -x foo.archi                          # Extract all files from foo.archi archive\
\n");
printf("\
archi -x -o outdir foo.archi                # Extract all files from foo.archi archive\n\
                                            # to outdir directory\
\n");
}


int main(int argc, char * argv[])
{
  int opt,opt_index;
  char * f_in = NULL;
  char * f_out = NULL;
  uint16_t wsize=ARCHI_WINDOW_SIZE;
  uint16_t bsize=ARCHI_BUFFER_SIZE;
  bool nquiet = true;
  bool reset = false;
//   bool reset = false;
  enum archi_op op = archi_op_nop;
  static struct option long_options[] = {
    {"help",            no_argument,            0, 'h'},
    {"extract",         no_argument,            0, 'x'},
    {"create",          no_argument,            0, 'c'},
    {"out-file",	required_argument, 	0, 'o'},
    {"window-size",	required_argument,	0, 'w'},
    {"buffer-size",	required_argument,	0, 'b'},
    {"quiet",		no_argument,            0, 'q'},
    {"reset",		no_argument,            0, 'r'}
  };
  while((opt = getopt_long(argc,argv,"hxcrqw:b:o:",long_options,&opt_index)) != -1)
  {
    switch(opt)
    {
      case 0:
        
        break;
      case 'c':
        op = archi_op_create;
        break;
      case 'x':
	op = archi_op_extract;
        break;
      case 'h':
      {
	print_help(argv[0]);
	exit(0);
	break;
      }
      case 'i':
      {
	f_in = optarg;
	break;
      }
      case 'o':
      {
	f_out = optarg;
	break;
      }
      case 'w':
      {
	int ws = atoi(optarg);
	if(ws<=0)
	{
	 fprintf(stderr,"archi: wrong window size\n"); 
	 exit(1);
	}
	wsize = (uint16_t)ws;
	break;
      }
      case 'b':
      {
	int bs = atoi(optarg);
	if(bs<=0)
	{
	 fprintf(stderr,"archi: wrong buffer size\n"); 
	 exit(1);
	}
	bsize = (uint16_t)bs;
	break;
      }
      case 'q':
	nquiet = false;
	break;
      case 'r':
	reset = true;
	break;
      case ':':
	break;
      case '?':
	exit(1);
        break;
    }
  }
  if(bsize>wsize)
  {
    fprintf(stderr,"archi: wrong buffer size\n"); 
    exit(1);
  }
  archi * A = new archi(nquiet);
  switch(op)
  {
    case archi_op_nop:
      fprintf(stderr,"archi: you must specify an operation -c or -x\n");
      print_help(argv[0]);
      exit(0);
      break;
    case archi_op_create:
    {
      A->encode(&argv[optind],(argc-optind),f_out,wsize,bsize,reset);
      break;
    }
    case archi_op_extract:
    {
      A->decode(argv[optind],f_out);
      break;
    }
  }
  delete A;
  return 0;
}